/**
 * Created with JetBrains WebStorm.
 * User: ishowshao
 * Date: 13-5-2
 */
var Observable = require('events').EventEmitter;

var Session = function () {
    this._id = String(+new Date()) + String(Math.random());
    this._valueCache = {};
    this._createDate = new Date();
};
Session.prototype.set = function (key, value) {
    this._valueCache[key] = value;
};
Session.prototype.get = function (key) {
    return this._valueCache[key];
};
Session.prototype.clear = function () {
    this._valueCache = {};
};
/**
 * 返回session id
 * @returns {String}
 */
Session.prototype.getId = function () {
    return this._id;
};
var Action = function (options) {
    this.GET = {};
    this.POST = {};
    this.COOKIE = {};
    this._request = options.request;
    this._response = options.response;
    this._controller = options.controller;
};
Action.prototype = Object.create(Observable.prototype);
Action.prototype.init = function () {
    var queryString = require('querystring');
    var postData = '';
    var that = this;

    var cookies = {};
    this._request.headers.cookie && this._request.headers.cookie.split(';').forEach(function (cookie) {
        var parts = cookie.split('=');
        cookies[parts[0].trim()] = (parts[1] || '').trim();
    });
    this.COOKIE = cookies;

    var method = this._request.method;
    if (method == 'POST') {
        this._request.on('data', function (chunk) {
            postData += chunk;
        }).on('end', function () {
            that.POST = queryString.parse(postData);
            that.emit('init');
        });
    } else if (method == 'GET') {
        this.GET = require('url').parse(this._request.url, true).query;
        this.emit('init');
    }
};
Action.prototype.header = function (name, value) {
    this._response.setHeader(name, value);
};
Action.prototype.echo = function (output) {
    this._response.write(output);
};
Action.prototype.end = function (output) {
    this._response.end(typeof output == 'undefined' ? '' : output);
};
Action.prototype.sessionStart = function () {
    if (this.COOKIE && this.COOKIE['chita-session']) {
        //this._session 直接从controller中取对象
        this._session = this._controller.getSessionById(this.COOKIE['chita-session']);
        if (!this._session) {
            this._session = new Session();
            this._controller.registerSession(this._session.getId(), this._session);
            this.header('Set-Cookie', 'chita-session=' + this._session.getId());
        }
    } else {
        this._session = new Session();
        this._controller.registerSession(this._session.getId(), this._session);
        this.header('Set-Cookie', 'chita-session=' + this._session.getId());
    }
};
Action.prototype.sessionSet = function (key, value) {
    this._session.set(key, value);
};
Action.prototype.sessionGet = function (key) {
    return this._session.get(key);
};
Action.prototype.sessionClear = function () {
    this._session.clear();
};

/**
 * 我实现的这套系统中，控制器是单件
 * @constructor
 */
var Controller = function () {
    this._actions = {};
    this._mimeTypes = {};
    this._publicPath = '';
    this._sessionContainer = {};
};

/**
 * 注册action
 * @param {String} action
 * @param {Function} callback
 */
Controller.prototype.on = function (action, callback) {
    this._actions[action] = {};
    this._actions[action].handler = callback;
};

/**
 * 处理客户端请求
 * @param request
 * @param response
 */
Controller.prototype.process = function (request, response) {
    var url = request.url;
    var path = require('url').parse(url, true).pathname;
    if (this.isStaticRequest(url)) {
        this._processStatic(request, response);
    } else {
        if (this._actions[path]) {
            (function (action, controller) {
                var a = new Action({
                    request: request,
                    response: response,
                    controller: controller
                });
                a.on('init', function () {
                    action.handler.call(a, a);
//                    response.end('');
                });
                a.init(); //主意这里的init里面是有异步也有同步，原本放在Action构造器中调用的，现在放在这里确保init事件能接收
            })(this._actions[path], this)
        }
    }
};
Controller.prototype._processStatic = function (request, response) {
    var urlInfo = this.parseStaticUrl(request.url);
    console.log(request);
    require('fs').stat(this._publicPath + urlInfo.pathname, function (err, stat) {
        console.log(stat);
    });
    require('fs').readFile(this._publicPath + urlInfo.pathname, {encoding: 'utf-8'}, function (error, data) {
        if (error) {
            console.log(error);
            response.writeHead(404, {
                'Content-Type': 'text/plain'
            });
            response.end('Not Found');
        } else {
            response.writeHead(200, urlInfo.mime);
            response.end(data);
        }
    });
};

/**
 * @param {String} url
 * @returns {{isStatic: boolean, pathname: string, ext: string, mime: object}}
 */
Controller.prototype.parseStaticUrl = function (url) {
    var parsed = {
        isStatic: false,
        pathname: '',
        ext: '',
        mime: {}
    };
    parsed.pathname = require('url').parse(url, true).pathname;
    var pathArray = parsed.pathname.split('.');
    parsed.ext = pathArray[pathArray.length - 1];
    if (this._mimeTypes[parsed.ext]) {
        parsed.isStatic = true;
        parsed.mime = this._mimeTypes[parsed.ext];
    }
    return parsed;
};

/**
 * Check if the url is a static request
 * @param {String} url
 * @returns {boolean}
 */
Controller.prototype.isStaticRequest = function (url) {
    var isStatic = false;
    var pathArray = require('url').parse(url, true).pathname.split('.');
    var ext = pathArray[pathArray.length - 1];
    if (this._mimeTypes[ext]) {
        isStatic = true;
    }
    return isStatic;
};

Controller.prototype.setMimeTypes = function (mime) {
    this._mimeTypes = mime;
};

/**
 * 设置公共文档路径
 * @param {String} path
 */
Controller.prototype.setPublicPath = function (path) {
    this._publicPath = path;
};

/**
 * 注册server级别session对象，只要server不重启就一直在，重复注册覆盖处理
 * @param {String} id
 * @param {Session} session
 */
Controller.prototype.registerSession = function (id, session) {
    this._sessionContainer[id] = session;
};

/**
 * @param {String} id
 * @returns {Session|null}
 */
Controller.prototype.getSessionById = function (id) {
    return this._sessionContainer[id] || null;
};

var Chita = {};

/**
 * @type {Object}
 */
Chita.mimeTypes = {
    html: {
        'Content-Type': 'text/html'
    },
    js: {
        'Content-Type': 'application/javascript'
    },
    css: {
        'Content-Type': 'text/css'
    },
    gif: {
        'Content-Type': 'image/gif'
    },
    jpg: {
        'Content-Type': 'image/jpeg'
    },
    png: {
        'Content-Type': 'image/png'
    },
    json: {
        'Content-Type': 'application/json'
    },
    txt: {
        'Content-Type': 'text/plain'
    }
};

Chita.config = {
    port: 8000,
    host: '127.0.0.1',
    encoding: 'utf-8'
};
Chita.setConfig = function (c) {
    this.config.port = c.port;
};

/**
 * Chita的http server是否在运行
 * @type {boolean}
 * @private
 */
Chita._running = false;

/**
 * 启动 http server
 * @returns {Chita}
 */
Chita.createServer = function () {
    var that = this;
    var http = require('http');
    this._init();
    if (!this._running) {
        http.createServer(function (request, response) {
            that.controller.process(request, response);
        }).listen(this.config.port, this.config.host);
        this._running = true;
    }
    return this;
};

/**
 * Chita的一些初始化工作
 * @private
 */
Chita._init = function () {
    this.controller = new Controller();
    this.controller.setMimeTypes(Chita.mimeTypes);
};

/**
 * 把publicPath设置为静态文件目录，并且让app自动检测静态请求并发送静态文件
 * @param {String} publicPath
 */
Chita.autoStatic = function (publicPath) {
    this.controller.setPublicPath(publicPath);
};

/**
 * 处理一个特定URL
 * @param {String} path
 * @param {Function} callback
 */
Chita.route = function (path, callback) {
    this.controller.on(path, callback);
};

module.exports = Chita;
